﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace RapidTestMapMaker
{
    public partial class MapDisplayUserControl : UserControl
    {
        public MapDisplayUserControl()
        {
            InitializeComponent();
        }

        private BigMap map;
        private TileSet tileset;

        public BigMap Map
        {
            get { return map; }
            set { map = value; }
        }

        public TileSet TileSet
        {
            get { return tileset; }
            set
            {
                if (tileset != null)
                {
                    tileset.TileChanged -= tileset_TileChanged;
                }
                tileset = value;
                if (tileset != null)
                {
                    tileset.TileChanged += tileset_TileChanged;
                }
            }
        }

        void tileset_TileChanged(object sender, EventArgs e)
        {
            Refresh();
        }

        private void MapDisplayUserControl_Paint(object sender, PaintEventArgs e)
        {
            try
            {
                Graphics g = e.Graphics;
                int l = e.ClipRectangle.Left / tileset.TileWidth + xOffset;
                int t = e.ClipRectangle.Top / tileset.TileHeight + yOffset;
                int r = e.ClipRectangle.Right / tileset.TileWidth + 1 + xOffset;
                int b = e.ClipRectangle.Bottom / tileset.TileHeight + 1 + yOffset;

                DrawMap(g, map, new Rectangle(l, t, r - l, b - t));
            }
            catch (Exception err)
            {
                int a = 5;
            }
        }

        public void DrawMap(Graphics g, BigMap map, bool DrawGrid = true)
        {
            DrawMap(g, map, Rectangle.Empty, DrawGrid);
        }
        public void DrawMap(Graphics g, BigMap map, Rectangle clip, bool DrawGrid = true)
        {
            Rectangle trimclip = clip;
            if (clip == Rectangle.Empty)
            {
                Rectangle b = map.ImageBounds;
                trimclip = new Rectangle(b.Left, b.Top, b.Width, b.Height);
            }
            foreach (MapLayer layer in map.Layers)
            {
                DrawLayer(g, layer, trimclip, DrawGrid);
            }
        }

        private void DrawLayer(Graphics g, MapLayer layer, Rectangle clip, bool DrawGrid)
        {
            int tw = tileset.TileWidth;
            int th = tileset.TileHeight;
            Rectangle clip2 = (layer.IsWall ? new Rectangle(clip.Left, clip.Top * 2, clip.Width, clip.Height * 2) : clip);

            layer.GetAllTilesInRectangle(clip2, (tile, x, y) =>
            {
                if (layer.IsWall)
                {
                    int wallWidth = 6;
                    int halfWall = wallWidth / 2;
                    if (tile == null) { return; }
                    Image wallImage = tile[x, y];
                    if (wallImage == null) { return; }
                    int x1 = (x - xOffset) * tw;
                    int y1 = ((y / 2) - yOffset) * th;
                    int x2 = x1 + tw;
                    int y2 = y1 + th;
                    Rectangle clipTile = Rectangle.Empty;
                    if (y % 2 == 0)
                    {
                        clipTile = new Rectangle(x1 - halfWall, y1, wallWidth, th);
                    }
                    else
                    {
                        clipTile = new Rectangle(x1, y1 - halfWall, tw, wallWidth);
                    }
                    try
                    {
                        g.DrawImage(tile[x, y], clipTile, 0, 0, tw, th, GraphicsUnit.Pixel);
                    }
                    catch (Exception ignored)
                    {
                        g.DrawLine(Pens.Red, x1, y1, x2, y2);
                        g.DrawLine(Pens.Red, x1, y2, x2, y1);
                        g.DrawRectangle(Pens.Red, x1, y1, x2 - x1, y2 - y1);
                    }
                }
                else
                {
                    int x1 = (x - xOffset) * tw;
                    int y1 = (y - yOffset) * th;
                    int x2 = x1 + tw;
                    int y2 = y1 + th;
                    if (tile == null)
                    {
                        if (DrawGrid)
                        {
                            g.DrawLine(Pens.Black, x1, y1, x2, y2);
                            g.DrawLine(Pens.Black, x1, y2, x2, y1);
                            g.DrawRectangle(Pens.Black, x1, y1, x2 - x1, y2 - y1);
                        }
                    }
                    else
                    {
                        try
                        {
                            g.DrawImage(tile[x, y], x1, y1, tw, th);
                        }
                        catch (Exception ignored)
                        {
                            g.DrawLine(Pens.Red, x1, y1, x2, y2);
                            g.DrawLine(Pens.Red, x1, y2, x2, y1);
                            g.DrawRectangle(Pens.Red, x1, y1, x2 - x1, y2 - y1);
                        }
                    }
                }
            });
        }

        private void ToggleHere(int mx, int my, bool set)
        {
            MapLayer active = map.ActiveLayer;
            int tw = tileset.TileWidth;
            int th = tileset.TileHeight;
            int x = mx / tw + xOffset;
            int y = my / th + yOffset;
            int ds = active.IsWall ? 2 : 1;
            int dy = 0;
            double ocx = Math.Abs(mx % tw);
            double ocy = Math.Abs(my % th);
            if (active.IsWall)
            {
                bool isCV = ocx < tw / 3;
                bool isCH = ocy < th / 3;
                bool isV = ocx < tw / 5;
                bool isH = ocy < th / 5;
                if (isCH && isCV || !isH && !isV)
                {
                    return;
                }
                dy = isH ? 1 : 0;
            }

            Tile orig = active[x, y * ds + dy];
            Tile newTile = set ? tileset.ActiveTile : null;
            if (orig != newTile)
            {
                active[x, y * ds + dy] = newTile;
                Invalidate(new Rectangle(mx - (tw * 2), my - (th * 2), tw * 4, th * 4));
            }
        }

        private bool mouseDown;
        private bool userIsPlacingTiles;

        private void MapDisplayUserControl_MouseDown(object sender, MouseEventArgs e)
        {
            mouseDown = true;
            userIsPlacingTiles = e.Button == System.Windows.Forms.MouseButtons.Left;
        }

        private void MapDisplayUserControl_MouseUp(object sender, MouseEventArgs e)
        {
            mouseDown = false;
            Invalidate();
        }

        private int lastX = int.MinValue;
        private int lastY = int.MinValue;
        private void MapDisplayUserControl_MouseMove(object sender, MouseEventArgs e)
        {
            int mx = e.X;
            int my = e.Y;
            if (lastX < 0 || lastY < 0)
            {
                lastX = mx;
                lastY = my;
            }
            if (mouseDown)
            {
                double dx = Math.Abs(mx - lastX);
                double dy = Math.Abs(my - lastY);
                double dist = dx + dy;
                double x = lastX;
                double y = lastY;
                int jiggle = (int)(dist / 4D);
                for (int jiggleX = -jiggle; jiggleX < jiggle; jiggleX += 5)
                {
                    for (int jiggleY = -jiggle; jiggleY < jiggle; jiggleY += 5)
                    {
                        for (double i = 0; i < dist; i += 5)
                        {
                            x = lastX + dx * (i / dist);
                            y = lastY + dy * (i / dist);
                            ToggleHere((int)x + jiggleX, (int)y + jiggleY, userIsPlacingTiles);
                        }
                    }
                }
                ToggleHere(mx, my, userIsPlacingTiles);
            }
            lastX = mx;
            lastY = my;
        }

        private int xOffset;
        private int yOffset;
        private int scrollSpeed = 5;

        private void buttonLeft_Click(object sender, EventArgs e)
        {
            xOffset -= scrollSpeed;
            Refresh();
        }

        private void buttonRight_Click(object sender, EventArgs e)
        {
            xOffset += scrollSpeed;
            Refresh();
        }

        private void buttonUp_Click(object sender, EventArgs e)
        {
            yOffset -= scrollSpeed;
            Refresh();
        }

        private void buttonDown_Click(object sender, EventArgs e)
        {
            yOffset += scrollSpeed;
            Refresh();
        }


    }
}
